/*
Copyright 2007 Luke Benstead

This file is part of slMath.

slMath is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

slMath is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser Public License for more details.

You should have received a copy of the GNU Lesser Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#ifdef __CPLUSPLUS
#include <cassert>
#else
#include <assert.h>
#endif

#include "math/vec4.h"
#include "math/plane.h"

slScalar slPlaneDot(const slPlane* pP, const slVec4* pV)
{
	//a*x + b*y + c*z + d*w

	return (pP->m_N.m_X * pV->m_X +
			pP->m_N.m_Y * pV->m_Y +
			pP->m_N.m_Z * pV->m_Z +
			pP->m_D * pV->m_W);
}

slScalar slPlaneDotCoord(const slPlane* pP, const slVec3* pV)
{
	return (pP->m_N.m_X * pV->m_X +
			pP->m_N.m_Y * pV->m_Y +
			pP->m_N.m_Z * pV->m_Z + pP->m_D);
}

slScalar slPlaneDotNormal(const slPlane* pP, const slVec3* pV)
{
	return (pP->m_N.m_X * pV->m_X +
			pP->m_N.m_Y * pV->m_Y +
			pP->m_N.m_Z * pV->m_Z);
}

slPlane* slPlaneFromPointNormal(slPlane* pOut, const slVec3* pPoint, const slVec3* pNormal)
{
	/*
		Planea = Nx
		Planeb = Ny
		Planec = Nz
		Planed = −N⋅P
	*/


	pOut->m_N.m_X = pNormal->m_X;
	pOut->m_N.m_Y = pNormal->m_Y;
	pOut->m_N.m_Z = pNormal->m_Z;
	pOut->m_D = -slVec3Dot(pNormal, pPoint);

	return pOut;
}

slPlane* slPlaneFromPoints(slPlane* pOut, const slVec3* p1, const slVec3* p2, const slVec3* p3)
{
	/*
	v = (B − A) × (C − A)
	n = 1⁄|v| v
	Outa = nx
	Outb = ny
	Outc = nz
	Outd = −n⋅A
	*/

	slVec3 n, v1, v2;
	slVec3Subtract(&v1, p2, p1); //Create the vectors for the 2 sides of the triangle
	slVec3Subtract(&v2, p3, p1);
	slVec3Cross(&n, &v1, &v2); //Use the cross product to get the normal

	slVec3Normalize(&pOut->m_N, &n); //Normalize it and assign to pOut->m_N
	pOut->m_D = slVec3Dot(slVec3Scale(&n, &n, -1.0), p1);

	return pOut;
}

slVec3*  slPlaneIntersectLine(slVec3* pOut, const slPlane* pP, const slVec3* pV1, const slVec3* pV2)
{
	/*
		n = (Planea, Planeb, Planec)
		d = V − U
		Out = U − d⋅(Pd + n⋅U)⁄(d⋅n) [iff d⋅n ≠ 0]
	*/

	assert(0);

	slVec3 d;
	slVec3Subtract(&d, pV2, pV1); //Get the direction vector

	if (slAbs(slVec3Dot(&pP->m_N, &d)) > slEpsilon)
	{
		//If we get here then the plane and line are parallel (i.e. no intersection)
		pOut = SLNULL; //Set to NULL

		return pOut;
	}

	//TODO: Continue here!

}

slPlane* slPlaneNormalize(slPlane* pOut, const slPlane* pP)
{
	slScalar l = 1.0 / slVec3Length(&pP->m_N); //Get 1/length
	slVec3Normalize(&pOut->m_N, &pP->m_N); //Normalize the vector and assign to pOut
	pOut->m_D = pP->m_D * l; //Scale the D value and assign to pOut

	return pOut;
}

slPlane* slPlaneScale(slPlane* pOut, const slPlane* pP, slScalar s)
{
	assert(0);
}

